<?php
    class Tree {

        private $db;
        private $table;
        private $options = array('parent_ref' => 'parent_id');
        private $cond;

        function __construct($table, $options = array()) {
            $ci = &get_instance();
            $this->table = $table;
            $this->db = $ci->db;
            foreach($options as $index => $option) {
                $this->options[$index] = $option;
            }
        }

        function getAll() {
            $query = $this->db->get($this->table);
            if($query->num_rows() == 0) {
                return FALSE;
            }

            return $query->result_array();
        }

        function getNodeByParam($param_name, $param_value, $fields = array('*')) {
            $query = $this->db->select($fields)->where($param_name, $param_value)->get($this->table);
            if($query->num_rows() == 0) {
                return FALSE;
            }

            if($query->num_rows() == 1) {
                return $query->row_array();
            }

            return $query->result_array();
        }

        function getNodesWhere($where, $fields = array('*')) {
            $query = $this->db->select($fields)->where($where)->get($this->table);
            if($query->num_rows() == 0) {
                return FALSE;
            }

            if($query->num_rows() == 1) {
                return $query->row_array();
            }

            return $query->result_array();
        }

        function getNode($id, $fields = array('*')) {
            return $this->getNodeByParam('id', $id, $fields);
        }

        function getChildNodes($id, $fields = array('*')) {
            return $this->getNodeByParam($this->options['parent_ref'], $id, $fields);
        }

        function hasChild($id) {
            $node = $this->getNodeByParam($this->options['parent_ref'], $id, array('id'));
            return ($node == FALSE) ? FALSE : TRUE;
        }

        function hasParent($id) {
            $node = $this->getNode($id, array('id', $this->options['parent_ref']));
            $child = $this->getNodeByParam('id', $node[$this->options['parent_ref']], array('id'));
            return (count($child) == 0) ? FALSE : TRUE;
        }

        function getAllParentNodes($id, $fields = array('*')) {
            static $ret = array();
            if($id == 1) return;
            $node = $this->getNode($id,$fields);
            if($node != FALSE) {
                $ret[] = $node;
                $this->getAllParentNodes($node[$this->options['parent_ref']], $fields);
            }
            return array_reverse($ret);
        }

        function getAllChildNodes($id, $fields = array('id'), $level = 0) {
            static $ret = array();
            $level++;
            $node = $this->getNode($id, $fields);
            if($node != FALSE) {
                $ret[$id] = $node;
                $childs = $this->getChildNodes($id, $fields);
                if($childs != FALSE) {
                    foreach($childs as $child) {
                        $this->getAllChildNodes($child['id'], $fields);
                    }
                }
            }
            return $ret;
        }
    }
?>